﻿using System;
using System.Linq;
using System.Reflection;
using System.Collections.Generic;

namespace Caramel.Entities.Testing
{
	public class ReferenceListProperty<T, TListEmement> : Property<T, IEnumerable<TListEmement>> where T : class, IEntity, new()
	{
		public ReferenceListProperty(PropertyInfo member, Func<IEnumerable<TListEmement>, IEnumerable<TListEmement>, bool> comparer)
			: base(member, comparer)
		{
		}

		public override void CheckValue(T expected, T actual)
		{
			// Both lists?
			var expectedList = this.GetValue(expected) as IEnumerable<TListEmement>;
			var actualList = this.GetValue(actual) as IEnumerable<TListEmement>;

			this.CheckListValue(expectedList, actualList);
		}

		private void CheckListValue(IEnumerable<TListEmement> expectedList, IEnumerable<TListEmement> actualList)
		{
			// Count
			if (expectedList.Count() != actualList.Count())
			{
				throw new ApplicationException(String.Format("Actual count ({0}) does not equal expected count ({1})", actualList.Count(), expectedList.Count()));
			}

			if (this.Comparer != null)
			{
				if (!this.Comparer(expectedList, actualList))
				{
					throw new ApplicationException("Actual and expected are not equal.");
				}
			}
			else
			{
				// 1 for 1 equality
				for (var i = 0; i < actualList.Count(); i++)
				{
					if (!actualList.ElementAt(i).Equals(expectedList.ElementAt(i)))
					{
						throw new ApplicationException(String.Format("Expected '{0}' but got '{1}' at position {2}", expectedList.ElementAt(i), actualList.ElementAt(i), i));
					}
				}
			}
		}
	}
}
